﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Linq;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace iChip.Hostpots.Commons
{
    public class Functions
    {
        /// <summary>
        /// Lấy IP từ request
        /// </summary>
        /// <returns></returns>
        public static string GetIPAddress()
        {
            System.Web.HttpContext context = System.Web.HttpContext.Current;
            string ipAddress = context.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

            if (!string.IsNullOrEmpty(ipAddress))
            {
                string[] addresses = ipAddress.Split(',');
                if (addresses.Length != 0)
                {
                    return addresses[0];
                }
            }

            return context.Request.ServerVariables["REMOTE_ADDR"];
        }

        /// <summary>
        /// Gửi Email
        /// </summary>
        /// <param name="body"></param>
        public static void SendMail(string body)
        {
            string toMail = ConfigurationManager.AppSettings["ToMail"];
            string subject = "Cảnh báo từ hệ thống Wifi Marketing iChip";
            string fromMail = ConfigurationManager.AppSettings["FromMail"].Split(',')[0];
            string password = ConfigurationManager.AppSettings["FromMail"].Split(',')[1];
            MailMessage oMail = new MailMessage(fromMail, toMail, subject, body); //first your adress, then the person you want to send it to. This order is important!
            SmtpClient oClient = new SmtpClient("smtp.gmail.com", 587); //this is where the difference is made between hotmail, gmail, and others.
            oMail.ReplyTo = new MailAddress(fromMail);
            oMail.From = new MailAddress(fromMail, "Wifi Marketing iChip");
            oClient.Credentials = new System.Net.NetworkCredential(fromMail, password);
            oClient.EnableSsl = true;
            oMail.IsBodyHtml = true;

            oClient.Send(oMail);

        }

        /// <summary>
        /// Lay description cua enum
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumValue"></param>
        /// <returns></returns>
        public static string GetDescriptionFromEnumValue<T>(object enumValue)
        {
            if (Enum.IsDefined(typeof(T), enumValue))
            {
                var value = (T)enumValue;
                DescriptionAttribute attribute = value.GetType()
                    .GetField(value.ToString())
                    .GetCustomAttributes(typeof(DescriptionAttribute), false)
                    .SingleOrDefault() as DescriptionAttribute;
                return attribute == null ? value.ToString() : attribute.Description;
            }
            else
            {
                return string.Empty;
            }
        }

        public static string GetValueFromEnumValue<T>(object enumValue)
        {
            if (Enum.IsDefined(typeof(T), enumValue))
            {
                var value = (T)enumValue;

                return value.ToString();
            }
            else
            {
                return "";
            }
        }

        public static List<SelectListItem> ReturnListFromEnum<T>()
        {
            var result = new List<SelectListItem>();
            IEnumerable<T> objList = Enum.GetValues(typeof(T)).Cast<T>();
            
            result = objList.Select(m => new SelectListItem
            {
                Text = GetDescriptionFromEnumValue<T>(m),
                Value = GetValueFromEnumValue<T>(m)
            }).ToList();
            return result;
        }

        //IEnumerable<iChip.Hotspots.Commons.Enums.UserType> userType = Enum.GetValues(typeof(iChip.Hotspots.Commons.Enums.UserType)).Cast<iChip.Hotspots.Commons.Enums.UserType>();
        //    model.User_TypeList = userType.Select(m => new SelectListItem
        //    {
        //        Text = iChip.Hostpots.Commons.Functions.GetDescriptionFromEnumValue<iChip.Hotspots.Commons.Enums.UserType>(m),
        //        Value = ((int)m).ToString()
        //    });

        public static string MD5Hash(string text)
        {
            MD5 md5 = new MD5CryptoServiceProvider();

            //compute hash from the bytes of text
            md5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(text));

            //get hash result after compute it
            byte[] result = md5.Hash;

            StringBuilder strBuilder = new StringBuilder();
            for (int i = 0; i < result.Length; i++)
            {
                //change it into 2 hexadecimal digits
                //for each byte
                strBuilder.Append(result[i].ToString("x2"));
            }

            return strBuilder.ToString();
        }
    }

    public class PasswordHash
    {
        // The following constants may be changed without breaking existing hashes.
        public const int SALT_BYTE_SIZE = 24;
        public const int HASH_BYTE_SIZE = 24;
        public const int PBKDF2_ITERATIONS = 1000;

        public const int ITERATION_INDEX = 0;
        public const int SALT_INDEX = 1;
        public const int PBKDF2_INDEX = 2;

        /// <summary>
        /// Creates a salted PBKDF2 hash of the password.
        /// </summary>
        /// <param name="password">The password to hash.</param>
        /// <returns>The hash of the password.</returns>
        public static string CreateHash(string password)
        {
            // Generate a random salt
            RNGCryptoServiceProvider csprng = new RNGCryptoServiceProvider();
            byte[] salt = new byte[SALT_BYTE_SIZE];
            csprng.GetBytes(salt);

            // Hash the password and encode the parameters
            byte[] hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
            return PBKDF2_ITERATIONS + ":" +
                Convert.ToBase64String(salt) + ":" +
                Convert.ToBase64String(hash);
        }

        /// <summary>
        /// Validates a password given a hash of the correct one.
        /// </summary>
        /// <param name="password">The password to check.</param>
        /// <param name="correctHash">A hash of the correct password.</param>
        /// <returns>True if the password is correct. False otherwise.</returns>
        public static bool ValidatePassword(string password, string correctHash)
        {
            // Extract the parameters from the hash
            char[] delimiter = { ':' };
            string[] split = correctHash.Split(delimiter);
            int iterations = Int32.Parse(split[ITERATION_INDEX]);
            byte[] salt = Convert.FromBase64String(split[SALT_INDEX]);
            byte[] hash = Convert.FromBase64String(split[PBKDF2_INDEX]);

            byte[] testHash = PBKDF2(password, salt, iterations, hash.Length);
            return SlowEquals(hash, testHash);
        }

        /// <summary>
        /// Compares two byte arrays in length-constant time. This comparison
        /// method is used so that password hashes cannot be extracted from
        /// on-line systems using a timing attack and then attacked off-line.
        /// </summary>
        /// <param name="a">The first byte array.</param>
        /// <param name="b">The second byte array.</param>
        /// <returns>True if both byte arrays are equal. False otherwise.</returns>
        private static bool SlowEquals(byte[] a, byte[] b)
        {
            uint diff = (uint)a.Length ^ (uint)b.Length;
            for (int i = 0; i < a.Length && i < b.Length; i++)
                diff |= (uint)(a[i] ^ b[i]);
            return diff == 0;
        }

        /// <summary>
        /// Computes the PBKDF2-SHA1 hash of a password.
        /// </summary>
        /// <param name="password">The password to hash.</param>
        /// <param name="salt">The salt.</param>
        /// <param name="iterations">The PBKDF2 iteration count.</param>
        /// <param name="outputBytes">The length of the hash to generate, in bytes.</param>
        /// <returns>A hash of the password.</returns>
        private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
        {
            Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt);
            pbkdf2.IterationCount = iterations;
            return pbkdf2.GetBytes(outputBytes);
        }
    }
}